package com.ossa.gateway.filter;

import cn.hutool.json.JSONUtil;
import com.ossa.gateway.feign.UaaFeignReactive;
import com.ossa.gateway.util.EncryptUtil;
import com.sun.security.auth.UserPrincipal;
import lombok.RequiredArgsConstructor;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.*;
import java.util.function.Consumer;

/**
 * @author issavior
 */
@Component
@RequiredArgsConstructor
public class HeaderHandlerFilter implements GlobalFilter {

    private final UaaFeignReactive uaaFeignReactive;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String path = exchange.getRequest().getURI().getPath();
        if (path.contains("/uaa")) {
            return chain.filter(exchange);
        }

        HttpHeaders headers = exchange.getRequest().getHeaders();
        String authorization = headers.getFirst("Authorization");
        String refreshToken = headers.getFirst("RefreshToken");

        if (StringUtils.isEmpty(authorization)) {
            return chain.filter(exchange);
        }
        Map<String, ?> stringMap;
        String newToken = authorization;
        try {

            stringMap = uaaFeignReactive.checkToken(authorization.substring(7));
        } catch (Throwable e) {
            stringMap = null;
        }

        if (StringUtils.isEmpty(stringMap)) {
            HashMap<String, String> hashMap = new HashMap<>();
            hashMap.put("client_id", "c1");
            hashMap.put("client_secret", "secret");
            hashMap.put("grant_type", "refresh_token");
            hashMap.put("refresh_token", refreshToken);
            ResponseEntity<OAuth2AccessToken> block;
            try {
                block = uaaFeignReactive.postAccessToken(new UserPrincipal("c1"), hashMap);
            } catch (Throwable throwable) {
                return chain.filter(exchange);
            }

            newToken = Objects.requireNonNull(block.getBody()).getValue();

            stringMap = uaaFeignReactive.checkToken(newToken);

        }
        String jsonStr = JSONUtil.toJsonStr(stringMap);

        ServerHttpRequest request = exchange.getRequest();
        ServerHttpRequest.Builder mutate = request.mutate();

        Consumer<HttpHeaders> httpHeaders = httpHeader -> {
            httpHeader.set("AUTH", EncryptUtil.encodeUTF8StringBase64(jsonStr));
        };

        ServerHttpRequest.Builder builder = mutate.headers(httpHeaders);
        ServerHttpRequest build = builder.build();
        ServerWebExchange webExchange = exchange.mutate().request(build).build();

        String finalNewToken = newToken;
        return chain.filter(webExchange).then(Mono.fromRunnable(() ->
        {
            ServerHttpResponse response = exchange.getResponse();
            response.getHeaders().add("Authorization", finalNewToken);
        }));

    }

}
